#include "mmap-utils.h"

MMap::MMap()
{
  orig_mmap_addr = 0;
  mmap_metadata = 0;
  mmap_addr = 0;
  mmap_size = 0;
}

bool MMap::open_mmap(const char* fn, bool writable, size_t create_mmap_size) 
{
  this->fn = fn;
  int fd = -1;
  bool file_exists = access(this->fn.c_str(), R_OK) == 0;
  int mmap_prot, mmap_flags;
  if (file_exists) {
    int fn_flag = O_RDONLY;
    if (writable) fn_flag = O_RDWR;
    fd = open(fn, fn_flag);
    struct stat fd_stat;
    fstat(fd, &fd_stat);
    this->mmap_size = fd_stat.st_size;
    mmap_prot = writable ? PROT_WRITE : PROT_READ;
    mmap_flags = MAP_SHARED;
  } else {
    fd = open(fn, O_RDWR | O_CREAT | O_TRUNC, 0644);
    size_t metadata_size = 4 * 1024; // metadata 4k
    this->mmap_size = create_mmap_size + metadata_size;
    // or lseek64
    lseek(fd, mmap_size - 1, SEEK_SET);
    write(fd, "", 1);
    mmap_prot = PROT_WRITE;
    mmap_flags = MAP_SHARED;
  }
  
  if (fd < 0) {
    return false;
  }
  
  orig_mmap_addr = (char*)mmap(0, mmap_size, mmap_prot, mmap_flags, fd, 0);
  mmap_metadata = orig_mmap_addr;
  size_t metadata_size = 4 * 1024; // metadata 4k
  mmap_addr = orig_mmap_addr + metadata_size;
  close(fd);
  return true;
}

void MMap::close_mmap() 
{
  munmap(orig_mmap_addr, mmap_size);
}
